import 'dart:math';

import 'package:flutter/cupertino.dart';
import 'package:lib_uikit/widgets/chart/model/chart_multiple_dot_data.dart';

import 'model/chart_dot_data.dart';
import 'model/chart_xy_data.dart';
import 'package:decimal/decimal.dart';

/// @Title  图表xy轴的值的工具类
/// @Author: bryce
/// @CreateDate: 2023年08月24日10:51:26
class ChartXYValueUtils {
  /// 计算图表的XY相关值
  /// isCurvedLine:是否是折线的曲线图（如果是曲线图则minY和maxY需要增大一个格，防止曲线越界）
  static ChartXYData calculateChartXYData(
    List<ChartDotData> dots, {
    // 需要展示的y轴分隔值，例如传了0，则y轴绝对值最小值为0,否则自动根据数据点计算最小值
    double? cutY,
    bool isCurvedLine = false,
    double? customMinY,
    double? customMaxY,
    // 需要添加的y轴上线间隔个数（例如柱状图上线有文案时，需要上下增大一格）
    int addYIntervalUpDownCount = 0,
    // y轴需要翻倍，在间隔小于1的时候翻10倍（这里外部调用方法的时候不要传这个参数，由此方法内部递归传入）
    int yMultiplier = 1,
    // x轴的固定间隔
    int? xInterval,
  }) {
    double dotMaxValueY = dots.reduce((first, second) {
      if (first.value > second.value) {
        return first;
      } else {
        return second;
      }
    }).value;

    double dotMinValueY = dots.reduce((first, second) {
      if (first.value < second.value) {
        return first;
      } else {
        return second;
      }
    }).value;

    return calculateChartXYDataByValue(
      dotMinValueY: dotMinValueY,
      dotMaxValueY: dotMaxValueY,
      dotLength: dots.length,
      cutY: cutY,
      isCurvedLine: isCurvedLine,
      customMinY: customMinY,
      customMaxY: customMaxY,
      addYIntervalUpDownCount: addYIntervalUpDownCount,
      yMultiplier: yMultiplier,
      xInterval: xInterval,
    );
  }

  /// 计算图表的XY相关值
  /// isCurvedLine:是否是折线的曲线图（如果是曲线图则minY和maxY需要增大一个格，防止曲线越界）
  static ChartXYData calculateChartXYDataByMultiplierDots(
    List<ChartMultipleDotData> dots, {
    // 需要展示的y轴分隔值，例如传了0，则y轴绝对值最小值为0,否则自动根据数据点计算最小值
    double? cutY,
    bool isCurvedLine = false,
    double? customMinY,
    double? customMaxY,
    // 需要添加的y轴上线间隔个数（例如柱状图上线有文案时，需要上下增大一格）
    int addYIntervalUpDownCount = 0,
    // y轴需要翻倍，在间隔小于1的时候翻10倍（这里外部调用方法的时候不要传这个参数，由此方法内部递归传入）
    int yMultiplier = 1,
    // x轴的固定间隔
    int? xInterval,
  }) {
    double dotMaxValueY = dots.reduce((first, second) {
      if (first.maxValue() > second.maxValue()) {
        return first;
      } else {
        return second;
      }
    }).maxValue();

    double dotMinValueY = dots.reduce((first, second) {
      if (first.minValue() < second.minValue()) {
        return first;
      } else {
        return second;
      }
    }).minValue();

    return calculateChartXYDataByValue(
        dotMinValueY: dotMinValueY,
        dotMaxValueY: dotMaxValueY,
        dotLength: dots.length,
        cutY: cutY,
        isCurvedLine: isCurvedLine,
        customMinY: customMinY,
        customMaxY: customMaxY,
        addYIntervalUpDownCount: addYIntervalUpDownCount,
        yMultiplier: yMultiplier,
        xInterval: xInterval);
  }

  /// 计算图表的XY相关值
  /// isCurvedLine:是否是折线的曲线图（如果是曲线图则minY和maxY需要增大一个格，防止曲线越界）
  static ChartXYData calculateChartXYDataByValue({
    required double dotMinValueY,
    required double dotMaxValueY,
    required int dotLength,
    // 需要展示的y轴分隔值，例如传了0，则y轴绝对值最小值为0,否则自动根据数据点计算最小值
    double? cutY,
    bool isCurvedLine = false,
    double? customMinY,
    double? customMaxY,
    // 需要添加的y轴上下间隔个数（例如柱状图上下有文案时，需要上下增大一格）
    int addYIntervalUpDownCount = 0,
    // y轴需要翻倍，在间隔小于1的时候翻10倍（这里外部调用方法的时候不要传这个参数，由此方法内部递归传入）
    int yMultiplier = 1,
    // x轴的固定间隔
    int? xInterval,
  }) {
    // 条形图限制的最大最小xy坐标
    double minX = 0, maxX = 0, minY = 0, maxY = 0;
    // y的最大最小值（不等于上面的minY和maxY）
    double minValueY = 0, maxValueY = 0;
    // xy轴的间隔值，（y间隔的是value值，x间隔的是日期）
    double yInterval = 50;
    int xRealInterval = 1;

    // 赋值x起点和终点
    maxX = dotLength - 1;
    // 赋值Y最小值和最大值
    if (null != customMinY && null != customMaxY) {
      minValueY = ((Decimal.tryParse('$customMinY') ?? Decimal.zero) * Decimal.fromInt(yMultiplier)).toDouble();
      maxValueY = ((Decimal.tryParse('$customMaxY') ?? Decimal.zero) * Decimal.fromInt(yMultiplier)).toDouble();
    } else {
      double dotMinValueYMultiplier =
          ((Decimal.tryParse('$dotMinValueY') ?? Decimal.zero) * Decimal.fromInt(yMultiplier)).toDouble();
      double dotMaxValueYMultiplier =
          ((Decimal.tryParse('$dotMaxValueY') ?? Decimal.zero) * Decimal.fromInt(yMultiplier)).toDouble();
      if (null == cutY) {
        minValueY = dotMinValueYMultiplier;
        maxValueY = dotMaxValueYMultiplier;
      } else {
        minValueY = min(cutY, dotMinValueYMultiplier);
        maxValueY = max(cutY, dotMaxValueYMultiplier);
      }
    }

    // 计算显示的y值的间隔值
    // yInterval = ChartXYValueUtils.calculateYInterval(maxValueY - minValueY, 5);
    yInterval = ChartXYValueUtils.calculateYIntervalV2(
      Decimal.parse((maxValueY - minValueY).toString()),
      Decimal.fromInt(5),
    ).toDouble();

    if (yMultiplier > 1) {
      // 如果大于1代表间隔是小于1的数字并且已经翻倍过
      // 这里不需要再翻倍，按照当前翻倍过的间隔计算返回
    } else {
      // 如果等于1代表没有翻倍过，可能是间隔是大于1的数或者是还没有计算过是否需要翻倍
      // 计算Y轴需要翻倍的倍数：在间隔小于1的时候翻10倍
      int yMultipleNew = calculateYIntervalMultiple(yInterval, maxValueY);
      if (yMultipleNew > 1) {
        return calculateChartXYDataByValue(
          dotMinValueY: dotMinValueY,
          dotMaxValueY: dotMaxValueY,
          dotLength: dotLength,
          isCurvedLine: isCurvedLine,
          customMinY: customMinY,
          customMaxY: customMaxY,
          addYIntervalUpDownCount: addYIntervalUpDownCount,
          yMultiplier: yMultipleNew,
          xInterval: xInterval,
        );
      }
    }

    // 计算显示的x值的间隔值
    xRealInterval = xInterval ?? (dotLength <= 4 ? 1 : (dotLength / 4).ceil());

    if (maxValueY - minValueY == 0) {
      if (minValueY % yInterval == 0) {
        minY = minValueY - yInterval * 2;
        maxY = maxValueY + yInterval * 2 + (yInterval / 100);
      } else {
        minY = ((minValueY / yInterval).floor()) * yInterval - yInterval * 1;
        maxY = ((maxValueY / yInterval).ceil()) * yInterval + yInterval * 1 + (yInterval / 100);
      }
    } else {
      // 控制图表的最大最小坐标
      minY = (minValueY % yInterval == 0) ? (minValueY) : ((minValueY / yInterval).floor()) * yInterval;
      maxY = (maxValueY % yInterval == 0)
          ? (maxValueY + (yInterval / 100))
          : ((maxValueY / yInterval).ceil()) * yInterval + (yInterval / 100);
    }

    if (addYIntervalUpDownCount > 0) {
      minY -= (addYIntervalUpDownCount * yInterval);
      maxY += (addYIntervalUpDownCount * yInterval);
    }

    // if ((maxY - minY) / yInterval < yLineBaseCount) {
    //   int temp = ((yLineBaseCount - (maxY - minY) / yInterval) / 2).ceil();
    //   minY -= temp;
    //   maxY += temp;
    // }

    return ChartXYData(
        minX: minX,
        maxX: maxX,
        minY: minY,
        maxY: maxY,
        minValueY: minValueY,
        maxValueY: maxValueY,
        yInterval: yInterval,
        xInterval: xRealInterval,
        yMultiplier: yMultiplier);
  }

  /// 计算y轴翻倍的倍数（如果y轴间隔太小的话，需要翻倍）
  static int calculateYIntervalMultiple(double yInterval, double maxValueY) {
    if (yInterval == 0) return 1;
    int yIntervalBaseCount = 1;
    while (yInterval < 1) {
      yInterval *= 10;
      yIntervalBaseCount *= 10;
    }
    return yIntervalBaseCount;
  }

  /// 计算Y轴显示间隔
  /// @param maxSpaceValue最大和最小值的差值
  /// @param internalCount横线数量
  // static double calculateYInterval(double maxSpaceValue, int internalCount) {
  //   // Y轴显示（判断Y轴显示间隔（horizontalInterval））：
  //   // 		最大差异值：maxSpaceValue = 最大数值减去最小数值；
  //   // 			1.1 maxSpaceValue<=70
  //   // 				间隔 = maxSpaceValue/7 向上取整
  //   // 			1.2 maxSpaceValue>70 && maxSpaceValue<=700
  //   // 				间隔 = maxSpaceValue/70 向上取整后*10
  //   // 			1.3 maxSpaceValue>700 && maxSpaceValue<=7000
  //   // 				间隔 = maxSpaceValue/700 向上取整后*100
  //   // 			1.4 maxSpaceValue>7000 && maxSpaceValue<=70000
  //   // 				间隔 = maxSpaceValue/7000 向上取整后*1000
  //   // 			1.5 maxSpaceValue>70000 && maxSpaceValue<=700000
  //   // 				间隔 = maxSpaceValue/70000 向上取整后*10000
  //   // 			1.6 maxSpaceValue>700000 && maxSpaceValue<=7000000
  //   // 				间隔 = maxSpaceValue/700000 向上取整后*100000
  //   if (maxSpaceValue == 0) {
  //     return 1;
  //   } else if (maxSpaceValue <= (internalCount * 0.000000000000001)) {
  //     return calculateYInterval(maxSpaceValue * 10000000000000000, internalCount) / 10000000000000000;
  //   } else if (maxSpaceValue <= (internalCount * 0.00000000000001)) {
  //     return calculateYInterval(maxSpaceValue * 1000000000000000, internalCount) / 1000000000000000;
  //   } else if (maxSpaceValue <= (internalCount * 0.0000000000001)) {
  //     return calculateYInterval(maxSpaceValue * 100000000000000, internalCount) / 100000000000000;
  //   } else if (maxSpaceValue <= (internalCount * 0.000000000001)) {
  //     return calculateYInterval(maxSpaceValue * 10000000000000, internalCount) / 10000000000000;
  //   } else if (maxSpaceValue <= (internalCount * 0.00000000001)) {
  //     return calculateYInterval(maxSpaceValue * 1000000000000, internalCount) / 1000000000000;
  //   } else if (maxSpaceValue <= (internalCount * 0.0000000001)) {
  //     return calculateYInterval(maxSpaceValue * 100000000000, internalCount) / 100000000000;
  //   } else if (maxSpaceValue <= (internalCount * 0.000000001)) {
  //     return calculateYInterval(maxSpaceValue * 10000000000, internalCount) / 10000000000;
  //   } else if (maxSpaceValue <= (internalCount * 0.00000001)) {
  //     return calculateYInterval(maxSpaceValue * 1000000000, internalCount) / 1000000000;
  //   } else if (maxSpaceValue <= (internalCount * 0.0000001)) {
  //     return calculateYInterval(maxSpaceValue * 100000000, internalCount) / 100000000;
  //   } else if (maxSpaceValue <= (internalCount * 0.000001)) {
  //     return calculateYInterval(maxSpaceValue * 10000000, internalCount) / 10000000;
  //   } else if (maxSpaceValue <= (internalCount * 0.00001)) {
  //     return calculateYInterval(maxSpaceValue * 1000000, internalCount) / 1000000;
  //   } else if (maxSpaceValue <= (internalCount * 0.0001)) {
  //     return calculateYInterval(maxSpaceValue * 100000, internalCount) / 100000;
  //   } else if (maxSpaceValue <= (internalCount * 0.001)) {
  //     return calculateYInterval(maxSpaceValue * 10000, internalCount) / 10000;
  //   } else if (maxSpaceValue <= (internalCount * 0.01)) {
  //     return calculateYInterval(maxSpaceValue * 1000, internalCount) / 1000;
  //   } else if (maxSpaceValue <= (internalCount * 0.1)) {
  //     return calculateYInterval(maxSpaceValue * 100, internalCount) / 100;
  //   } else if (maxSpaceValue <= (internalCount * 1)) {
  //     return calculateYInterval(maxSpaceValue * 10, internalCount) / 10;
  //   } else if (maxSpaceValue <= (internalCount * 10)) {
  //     return (maxSpaceValue / internalCount).ceil().toDouble();
  //   } else if (maxSpaceValue <= (internalCount * 100)) {
  //     return ((maxSpaceValue / (internalCount * 10)).ceil()) * 10;
  //   } else if (maxSpaceValue <= (internalCount * 1000)) {
  //     return ((maxSpaceValue / (internalCount * 100)).ceil()) * 100;
  //   } else if (maxSpaceValue <= (internalCount * 10000)) {
  //     return ((maxSpaceValue / (internalCount * 1000)).ceil()) * 1000;
  //   } else if (maxSpaceValue <= (internalCount * 100000)) {
  //     return ((maxSpaceValue / (internalCount * 10000)).ceil()) * 10000;
  //   } else if (maxSpaceValue <= (internalCount * 1000000)) {
  //     return ((maxSpaceValue / (internalCount * 100000)).ceil()) * 100000;
  //   } else if (maxSpaceValue <= (internalCount * 10000000)) {
  //     return ((maxSpaceValue / (internalCount * 1000000)).ceil()) * 1000000;
  //   } else if (maxSpaceValue <= (internalCount * 100000000)) {
  //     return ((maxSpaceValue / (internalCount * 10000000)).ceil()) * 10000000;
  //   } else if (maxSpaceValue <= (internalCount * 1000000000)) {
  //     return ((maxSpaceValue / (internalCount * 100000000)).ceil()) * 100000000;
  //   } else if (maxSpaceValue <= (internalCount * 10000000000)) {
  //     return ((maxSpaceValue / (internalCount * 1000000000)).ceil()) * 1000000000;
  //   } else if (maxSpaceValue <= (internalCount * 100000000000)) {
  //     return ((maxSpaceValue / (internalCount * 10000000000)).ceil()) * 10000000000;
  //   } else if (maxSpaceValue <= (internalCount * 1000000000000)) {
  //     return ((maxSpaceValue / (internalCount * 100000000000)).ceil()) * 100000000000;
  //   } else if (maxSpaceValue <= (internalCount * 10000000000000)) {
  //     return ((maxSpaceValue / (internalCount * 1000000000000)).ceil()) * 1000000000000;
  //   } else if (maxSpaceValue <= (internalCount * 100000000000000)) {
  //     return ((maxSpaceValue / (internalCount * 10000000000000)).ceil()) * 10000000000000;
  //   } else if (maxSpaceValue <= (internalCount * 1000000000000000)) {
  //     return ((maxSpaceValue / (internalCount * 100000000000000)).ceil()) * 100000000000000;
  //   } else if (maxSpaceValue <= (internalCount * 10000000000000000)) {
  //     return ((maxSpaceValue / (internalCount * 1000000000000000)).ceil()) * 1000000000000000;
  //   } else if (maxSpaceValue <= (internalCount * 100000000000000000)) {
  //     return ((maxSpaceValue / (internalCount * 10000000000000000)).ceil()) * 10000000000000000;
  //   } else if (maxSpaceValue <= (internalCount * 1000000000000000000)) {
  //     return ((maxSpaceValue / (internalCount * 100000000000000000)).ceil()) * 100000000000000000;
  //   } else {
  //     // 用于计算的基数
  //     double base = 10;
  //     // 找到合适的指数
  //     int exponent = (log(maxSpaceValue) / log(base)).floor();
  //     // 计算间隔的除数
  //     num divisor = pow(base, (exponent - exponent % internalCount));
  //     // 计算并返回间隔
  //     return (maxSpaceValue / divisor).ceilToDouble() * pow(base, (exponent % internalCount));
  //   }
  // }

  // static double calculateYInterval2(double maxSpaceValue, int internalCount) {
  //   if (maxSpaceValue <= 0) {
  //     return 1.0;
  //   }
  //   // 用于计算的基数
  //   double base = 10;
  //   // 找到合适的指数
  //   int exponent = (log(maxSpaceValue) / log(base)).floor();
  //   // 计算间隔的除数
  //   num divisor = pow(base, (exponent - exponent % internalCount));
  //   // 计算并返回间隔
  //   return (maxSpaceValue / divisor).ceilToDouble() * pow(base, (exponent % internalCount));
  // }

  /// 计算Y轴显示间隔
  /// @param maxSpaceValue最大和最小值的差值
  /// @param internalCount横线数量
  static Decimal calculateYIntervalV2(Decimal maxSpaceValue, Decimal internalCount) {
    if (maxSpaceValue == Decimal.zero) {
      return Decimal.one;
    }

    int exponent = 1;
    while (true) {
      if (maxSpaceValue > internalCount) {
        final base = Decimal.fromInt(10);
        if (maxSpaceValue > base.pow(exponent).toDecimal() * internalCount) {
          exponent++;
          continue;
        }
        final multiplier = base.pow(exponent - 1).toDecimal();
        return (maxSpaceValue / (internalCount * multiplier)).ceil().toDecimal() * multiplier;
      } else {
        final base = Decimal.parse('0.1');
        final value = base.pow(exponent).toDecimal(scaleOnInfinitePrecision: exponent) * internalCount;
        if (maxSpaceValue <= value) {
          exponent++;
          continue;
        }
        final multiplier = base.pow(exponent).toDecimal(scaleOnInfinitePrecision: exponent);
        return (maxSpaceValue / (internalCount * multiplier)).ceil().toDecimal() * multiplier;
      }
    }
  }
}
